#ifndef STX_ALGORITHM_ADVANCE_HPP
#define STX_ALGORITHM_ADVANCE_HPP

#include <iterator>

namespace stx {

template <class Iterator, class Difference>
inline void
advance_impl(Iterator& where, Difference offset, std::input_iterator_tag)
{
    for (; 0 < offset; --offset) {
        ++where;
    }
}

template <class ForwardIterator, class Difference>
inline void
advance_impl(ForwardIterator& where, Difference offset, std::forward_iterator_tag)
{
    for (; 0 < offset; --offset) {
        ++where;
    }
}

template <class BidirectionalIterator, class Difference>
inline void
advance_impl(BidirectionalIterator& where, Difference offset, std::bidirectional_iterator_tag)
{
    for (; 0 < offset; --offset) {
        ++where;
    }
    for (; offset < 0; ++offset) {
        --where;
    }
}

template <class RandomAccessIterator, class Difference>
inline void
advance_impl(RandomAccessIterator& where, Difference offset, std::random_access_iterator_tag)
{
    where += offset;
}

template <class Iterator, class Difference>
inline void
advance(Iterator& where, Difference offset)
{
    advance_impl(where, offset, typename std::iterator_traits<Iterator>::iterator_category());
}

} // namespace stx

#endif // STX_ALGORITHM_ADVANCE_HPP
